package com.scau.phr.business.auth.service;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.scau.phr.sdk.aliMsg.AliMessageService;
import com.scau.phr.business.auth.utils.IdCardValidator;
import com.scau.phr.common.exceptions.ErrorCode;
import com.scau.phr.common.exceptions.ServiceException;
import com.scau.phr.domain.entity.User;
import com.scau.phr.domain.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * 提供认证相关服务
 * @author yuzhiyi
 * @date 2018/7/17 20:43
 */
@Service
public class AuthService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private AliMessageService messageService;

    @Autowired
    @Qualifier("Md5Encipher")
    private Encipher encipher; //密码加密

    IdCardValidator idCardValidator = new IdCardValidator(); //身份证验证工具类

    private Cache<String,CodeMessage> cache;    //验证码缓存

    private static final int TIMEOUT_DURATION = 5; //超时时间

    private static final long TIMEOUT_TIMESTAMP = TIMEOUT_DURATION * 60 * 1000;

    private static final long ONE_MINUTE = 60 * 1000;

    public AuthService(){
        //初始化验证码缓存
        cache = CacheBuilder
                .newBuilder()
                .expireAfterWrite(TIMEOUT_DURATION, TimeUnit.MINUTES)  //五分钟之内失效
                .maximumSize(1000)                                     //最多1000个实例，防止内存泄露
                .build();
    }


    /**
     * 判断是否存在用户
     * @param phone 手机号
     * @return 若存在返回ture，否则返回false
     */
    public boolean existUser(String phone){
        return userMapper.selectById(phone) != null;
    }

    /**
     * 判断用户的验证码是否正确
     * @param phone 手机号
     * @param code 验证码
     * @return 若正确返回true，否则返回false
     */
    public boolean isValidCode(String phone,String code){
        CodeMessage codeMessage = cache.getIfPresent(phone);
        if (codeMessage == null){
            return false;
        }
        //判断手机和验证码是否正确
        if (!codeMessage.getPhone().equals(phone) || !codeMessage.getCode().equals(code)){
            return false;
        }
        //判断是否超时
        long currentTime = System.currentTimeMillis();
        if (codeMessage.getTimestamp() + TIMEOUT_TIMESTAMP >= currentTime){
            return true;
        }
        return false;
    }

    /**
     * 清空某个用户的验证码缓存信息
     * @param phone 手机号码
     */
    public void removeCodeCache(String phone){
        cache.invalidate(phone);
    }

    /**
     * 发送验证信息
     * @param phone 手机
     * @param content 验证信息
     */
    public void sendVerifyMeseage(String phone,String content){
        CodeMessage oldMessage = cache.getIfPresent(phone);
        //如果在一分钟内重复请求，那么将抛出请求过快的Exception
        if (oldMessage != null){
            if (oldMessage.getTimestamp() + ONE_MINUTE > System.currentTimeMillis()){
                throw new ServiceException(ErrorCode.MSG_REQ_TOO_FAST_ERROR);
            }
        }
        messageService.send(phone, content);
        CodeMessage codeMessage = new CodeMessage(phone,content);
        cache.put(phone,codeMessage);
    }

    /**
     * 判断密码是否正确
     * @param phone 手机号
     * @param password 密码
     * @return 如果用户不存在或者密码错误返回false，否则返回true
     */
    public boolean isValidPassword(String phone,String password){
        User user = userMapper.selectById(phone);
        if (user == null){
            return false;
        }
        String target = user.getPassword();
        String input = encipher.encrypt(password);
        return target.equals(input);
    }

    /**
     * 验证身份证号码是否合法
     * @param idCardNumber 身份证号码
     * @return 返回验证码是否合法
     */
    public boolean isValidIdCard(String idCardNumber){
        return idCardValidator.isValidatedAllIdcard(idCardNumber);
    }



    /**
     * 加密密码
     * @param password 未加密的密码
     * @return 加密后的密码
     */
    public String encryptPassword(String password){
        return encipher.encrypt(password);
    }



    /**
     * 验证码信息类
     */
    private class CodeMessage{
        private String phone;
        private String code;
        private long timestamp;//颁发时间

        CodeMessage(String phone, String code){
            this.phone = phone;
            this.code = code;
            this.timestamp = System.currentTimeMillis();
        }

        public String getPhone() {
            return phone;
        }

        public void setPhone(String phone) {
            this.phone = phone;
        }

        public String getCode() {
            return code;
        }

        public void setCode(String code) {
            this.code = code;
        }

        public long getTimestamp() {
            return timestamp;
        }

        public void setTimestamp(long timestamp) {
            this.timestamp = timestamp;
        }
    }

}
